iT邦幫忙

2026 iThome 鐵人賽

DAY 5
0
Build on Google AI

用 Google AI 生態系 30 天從零打造一個全棧 AI SaaS 服務系列 第 5

Day 05 -【雲端基底】初始化 Google Cloud & Firebase 專案架構:安全金鑰管理與 IAM 權限配置實戰

  • 分享至 

  • xImage
  •  

在 AI SaaS 的開發過程中,最容易讓獨立開發者栽跟頭的往往不是前端畫面或 Prompt 設計,而是雲端基礎設施的安全性與金鑰治理

社群上屢見不鮮的悲劇:某開發者誤將包含無限制額度的 Gemini API Key 或 GCP Service Account JSON 上傳至公開的 GitHub 倉庫,數小時內被自動化爬蟲掃描,產生數千美元的惡意調用帳單;或者前端直接調用未經授權驗證的後端端點,導致資料庫配額瞬間被刷爆。

在昨天的 [Day 04] 中,我們為 IDE 建立了嚴格的 Vibe Coding 規範。今天我們將踏出本地端,前往雲端戰場,實戰初始化 Google Cloud Platform (GCP)Firebase 專案架構,建立起防禦縱深兼備的金鑰管理與 IAM 權限體系。


🏗️ 雙核心雲端架構:GCP 與 Firebase 的共生關係

許多初學者常困惑:「我到底該在 Google Cloud Console 開專案,還是在 Firebase Console 開專案?」

在 Google 生態系中,每一個 Firebase 專案本質上就是一個完整的 Google Cloud 專案。最佳工作流是:

  1. 先至 Firebase Console 建立專案(命名為 omnivibe-ai-prod)。
  2. Firebase 會自動在底層建立同名的 GCP 專案,享有相同的專案 ID、計費帳戶(Billing Account)與 IAM 組織結構。
  3. 升級至 Blaze 計費方案(Pay-as-you-go):啟用 Blaze 方案不會立即扣款(各項服務仍有免費配額),但這是調用 Gemini API、Firebase App Hosting 與 Cloud Functions 外網連線的必要前提。

🔑 雙軌憑證策略:前端公開與後端機密的嚴格劃分

在全端 Next.js 架構下,環境變數必須嚴格劃分為公開客戶端(Client-side)伺服器私鑰(Server-side)兩套軌道:

憑證類型 代表變數 儲存位置 暴露風險 防禦機制
前端配置 (Client) NEXT_PUBLIC_FIREBASE_* 客戶端瀏覽器 Bundle 公開無害 依賴 Firebase Security Rules 嚴格校驗 UID
AI 大腦金鑰 (Server) GEMINI_API_KEY 僅限 Next.js 後端環境 極度危險 GCP API 限制特定 API 與 IP 範圍
後端管理憑證 (Server) FIREBASE_SERVICE_ACCOUNT_KEY 僅限 Next.js 後端環境 最高權限 IAM 最小權限原則、禁止 Hardcode 於代碼中

🛡️ 實戰第一步:取得與鎖定 Gemini API Key

  1. 登入 Google AI Studio,點擊 Get API key
  2. 選擇剛剛建立的 omnivibe-ai-prod 專案生成金鑰。
  3. 關鍵防護(API Key Restrictions)
  • 進入 Google Cloud Console > 憑證 (Credentials)
  • 找到該把 API Key,將名稱修改為 OmniVibe_Gemini_ServerKey
  • API 限制(API Restrictions):不要選「不限制」,勾選 Restrict key,並在下拉選單中僅勾選「Generative Language API」。如此一來,即使金鑰意外洩漏,攻擊者也無法拿它去開高規格 GPU 運算執行個體。

⚙️ 實戰第二步:產出 Firebase Admin SDK 服務帳戶

為了讓 Next.js 後端能安全地驗證使用者 JWT、讀寫 Firestore 與管理 Storage,我們需要配置 Firebase Admin SDK:

  1. 進入 Firebase Console > 專案設定 (Project Settings) > 服務帳戶 (Service Accounts)
  2. 點擊 產生新的私密金鑰 (Generate new private key),下載得到的 JSON 檔案。
  3. 安全規範:切勿將此 JSON 檔案放在專案目錄內提交至 Git!
  4. 在本地開發時,將 JSON 內容轉為單行字串或個別參數存入 .env.local
# ==========================================
# Client Side (公開至前端,受 Security Rules 保護)
# ==========================================
NEXT_PUBLIC_FIREBASE_API_KEY="AIzaSy_YOUR_FIREBASE_WEB_API_KEY_HERE"
NEXT_PUBLIC_FIREBASE_AUTH_DOMAIN="your-project-id.firebaseapp.com"
NEXT_PUBLIC_FIREBASE_PROJECT_ID="your-project-id"
NEXT_PUBLIC_FIREBASE_STORAGE_BUCKET="your-project-id.appspot.com"
NEXT_PUBLIC_FIREBASE_MESSAGING_SENDER_ID="123456789012"
NEXT_PUBLIC_FIREBASE_APP_ID="1:123456789012:web:abcdef1234567890"

# ==========================================
# Server Side Only (機密金鑰,絕對不可加上 NEXT_PUBLIC_ 前綴)
# ==========================================
GEMINI_API_KEY="AIzaSy_YOUR_GEMINI_API_KEY_HERE"
FIREBASE_ADMIN_PROJECT_ID="your-project-id"
FIREBASE_ADMIN_CLIENT_EMAIL="firebase-adminsdk-xxxxx@your-project-id.iam.gserviceaccount.com"
FIREBASE_ADMIN_PRIVATE_KEY="-----BEGIN PRIVATE KEY-----\nYOUR_ACTUAL_RSA_PRIVATE_KEY_CONTENT_HERE\n-----END PRIVATE KEY-----\n"

同時,建立一份 .env.example 提交至 Git 倉庫,作為團隊與部署時的範本:

# 複製設定範本
cp .env.example .env.local

並確認 .gitignore 包含以下規則:

.env
.env.local
.env.*.local
*.pem
serviceAccountKey.json


🧪 實戰第三步:建立後端單例初始化與連通測試(Smoke Test)

src/lib 目錄下,透過模組化封裝 Firebase Admin 與 Gemini 實例,避免 Next.js 在開發模式(Hot Reload)下重複初始化連線池。

1. Firebase Admin 初始化 (src/lib/firebase-admin.ts)

import { initializeApp, getApps, cert } from 'firebase-admin/app';
import { getFirestore } from 'firebase-admin/firestore';
import { getAuth } from 'firebase-admin/auth';

const privateKey = process.env.FIREBASE_ADMIN_PRIVATE_KEY
  ? process.env.FIREBASE_ADMIN_PRIVATE_KEY.replace(/\\n/g, '\n')
  : undefined;

if (!getApps().length) {
  initializeApp({
    credential: cert({
      projectId: process.env.FIREBASE_ADMIN_PROJECT_ID,
      clientEmail: process.env.FIREBASE_ADMIN_CLIENT_EMAIL,
      privateKey: privateKey,
    }),
  });
}

export const adminDb = getFirestore();
export const adminAuth = getAuth();

2. 健康檢查 API Route (src/app/api/health/route.ts)

透過一支簡單的 Route Handler,一次驗證環境變數與雲端憑證是否正確就位:

import { NextResponse } from 'next/server';
import { GoogleGenerativeAI } from '@google/generative-ai';
import { adminDb } from '@/lib/firebase-admin';

export async function GET() {
  try {
    // 1. 驗證 Firebase Admin 連通性
    const collections = await adminDb.listCollections();

    // 2. 驗證 Gemini API 連通性
    const genAI = new GoogleGenerativeAI(process.env.GEMINI_API_KEY || '');
    const model = genAI.getGenerativeModel({ model: 'gemini-1.5-flash' });
    const aiResult = await model.generateContent('ping');
    const aiResponse = aiResult.response.text();

    return NextResponse.json({
      status: 'healthy',
      timestamp: new Date().toISOString(),
      firebaseConnected: true,
      geminiResponse: aiResponse.trim(),
    });
  } catch (error: any) {
    return NextResponse.json(
      {
        status: 'unhealthy',
        error: error.message,
      },
      { status: 500 }
    );
  }
}

啟動專案執行 npm run dev 並造訪 http://localhost:3000/api/health,若回傳 status: "healthy",代表我們的後端與 Google AI / Firebase 雲端體系已正式打通,全棧地基建造完成!


至此,第一篇章【思維重塑與產品藍圖】(Day 01 - Day 05)已圓滿告一段落。我們從 Vibe Coding 概念發想、梳理 PRD、敲定全棧架構、配置 IDE Rules,到今天完成雲端安全基底的搭建。

從明天開始,我們將正式邁入【第二篇:Google AI 核心引擎與 Prompt 工坊】!

明天(Day 06),我們將深入 Google AI Studio:親手打造 OmniVibe AI 的第一支核心 System Prompt,實戰溫度值(Temperature)、Top-P 與安全設定調優,讓 Gemini 成為最懂內容提煉的專業大腦!


上一篇
Day 04 -【開發環境】現代 Vibe Coding 環境配置實戰:打造百發百中的 AI 協作 IDE 與 System Rules
下一篇
Day 06 -【AI Studio】走進 Google AI Studio:親手打造 OmniVibe AI 核心 System Prompt 與參數調優實戰
系列文
用 Google AI 生態系 30 天從零打造一個全棧 AI SaaS 服務7
圖片
  熱門推薦
圖片
{{ item.channelVendor }} | {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言